home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 11
/
Mac Magazin and MacEasy Magazine CD - Issue 11.iso
/
Sharewarebibliothek
/
Entwickler
/
WASTE 1.1b1 Distribution
/
WASTE Source
/
WESelecting.p
< prev
next >
Wrap
Text File
|
1995-06-01
|
46KB
|
1,651 lines
unit WESelecting;
{ WASTE PROJECT }
{ Drawing Selections, Activating, Updating, Scrolling, etc. }
{ Copyright © 1993-1995 Marco Piovanelli }
{ All Rights Reserved }
interface
uses
WELineLayout;
function WEGetOffset (thePoint: LongPt;
var edge: SignedByte;
hWE: WEHandle): LongInt;
procedure WEGetPoint (offset: LongInt;
var thePoint: LongPt;
var lineHeight: Integer;
hWE: WEHandle);
function WEGetHiliteRgn (rangeStart, rangeEnd: LongInt;
hWE: WEHandle): RgnHandle;
procedure _WEDrawCaret (offset: LongInt;
hWE: WEHandle);
procedure _WEBlinkCaret (hWE: WEHandle);
procedure _WEHiliteRange (rangeStart, rangeEnd: LongInt;
hWE: WEHandle);
procedure WEUpdate (updateRgn: RgnHandle;
hWE: WEHandle);
procedure WEScroll (hOffset, vOffset: LongInt;
hWE: WEHandle);
function _WEScrollIntoView (offset: LongInt;
hWE: WEHandle): Boolean;
procedure WESelView (hWE: WEHandle);
procedure WEActivate (hWE: WEHandle);
procedure WEDeactivate (hWE: WEHandle);
function WEIsActive (hWE: WEHandle): Boolean;
procedure _WEDoArrowKey (arrow: Integer;
modifiers: Integer;
hWE: WEHandle);
function WEAdjustCursor (mouseLoc: Point;
mouseRgn: RgnHandle;
hWE: WEHandle): Boolean;
procedure WEIdle (var maxSleep: LongInt;
hWE: WEHandle);
procedure WESetSelection (selStart, selEnd: LongInt;
hWE: WEHandle);
procedure WESetAlignment (alignment: SignedByte;
hWE: WEHandle);
procedure WEFindWord (offset: LongInt;
edge: SignedByte;
var wordStart, wordEnd: LongInt;
hWE: WEHandle);
procedure WEFindLine (offset: LongInt;
edge: SignedByte;
var lineStart, lineEnd: LongInt;
hWE: WEHandle);
function WECharByte (offset: LongInt;
hWE: WEHandle): Integer;
function WECharType (offset: LongInt;
hWE: WEHandle): Integer;
implementation
uses
LowMem, QDOffscreen, ToolUtils;
{ If WASTE_OBJECTS_ARE_GLYPHS is TRUE, WEGetOffset treats embedded objects }
{ like ordinary glyphs and never returns kObjectEdge in the edge parameter: }
{ as a result, clicking in the middle of an object always positions the caret either }
{ to the left or to the right of the object. }
{ If WASTE_OBJECTS_ARE_GLYPHS is FALSE, WEGetOffset returns kObjectEdge in }
{ the edge parameter when thePoint is in the middle half of an object: as a result, }
{ clicking in the middle of an object immediately _selects_ the object, so that a second }
{ click immediately following triggers the 'clik' callback (this can be handy to make }
{ sound objects play when they are double-clicked. }
{$SETC WASTE_OBJECTS_ARE_GLYPHS = FALSE}
const
{ values for _WEArrowOffset action parameter: }
{ plain arrow keys }
kGoLeft = 0;
kGoRight = 1;
kGoUp = 2;
kGoDown = 3;
{ modifiers }
kOption = 4;
kCommand = 8;
{ option + arrow combos }
kGoWordStart = kGoLeft + kOption;
kGoWordEnd = kGoRight + kOption;
kGoTextStart = kGoUp + kOption;
kGoTextEnd = kGoDown + kOption;
{ command + arrow combos }
kGoLineStart = kGoLeft + kCommand;
kGoLineEnd = kGoRight + kCommand;
kGoPageStart = kGoUp + kCommand;
kGoPageEnd = kGoDown + kCommand;
{$IFC GENERATINGCFM}
procedure _WEClearHiliteBit;
begin
LMSetHiliteMode(BAND(LMGetHiliteMode, $7F));
end; { _WEClearHiliteBit }
{$ELSEC}
procedure _WEClearHiliteBit;
inline
$08B8, $0007, $0938; { bclr #7, HiliteMode }
{$ENDC}
function WEGetOffset (thePoint: LongPt;
var edge: SignedByte;
hWE: WEHandle): LongInt;
{ given a long point in local coordinates, }
{ find the text offset corresponding to the nearest glyph }
var
pWE: WEPtr;
lineIndex: LongInt;
hPos: Fixed;
pixelWidth: Fixed;
saveWELock: Boolean;
function SLPixelToChar (pLine: LinePtr;
pAttrs: WERunAttributesPtr;
pSegment: Ptr;
segmentStart, segmentLength: LongInt;
styleRunPosition: JustStyleCode): Boolean;
var
slop, objectWidth, subWidth, oldWidth: Fixed;
cType: Integer;
begin
SLPixelToChar := false;
{ if this is the first style run on the line, subtract pen indent from pixelWidth }
if (styleRunPosition <= leftStyleRun) then
pixelWidth := pixelWidth - BSL(_WECalcPenIndent(pLine^.lineSlop, pWE^.alignment), 16);
{ if pixelWidth is gone negative already, the point is on the trailing edge of first glyph }
if (pixelWidth < 0) then
begin
WEGetOffset := segmentStart;
edge := kTrailingEdge;
SLPixelToChar := true;
Exit(SLPixelToChar);
end;
oldWidth := pixelWidth;
if (pAttrs^.runStyle.tsObject <> kNullObject) then
begin
{ EMBEDDED OBJECT }
{ calculate object width as Fixed }
objectWidth := BSL(WEObjectDescHandle(pAttrs^.runStyle.tsObject)^^.objectSize.h, 16);
{ subtract object width from pixelWidth }
pixelWidth := pixelWidth - objectWidth;
{$IFC WASTE_OBJECTS_ARE_GLYPHS}
{ find out whether the point is in the leftmost half of the object, }
{ in the rightmost half or past the object }
subWidth := BSR(objectWidth, 1); { divide by two }
if (pixelWidth + subWidth < 0) then
begin
WEGetOffset := segmentStart;
edge := kLeadingEdge; { point is in leftmost half of object }
end
else
begin
WEGetOffset := segmentStart + 1;
if (pixelWidth < 0) then
edge := kTrailingEdge { point is in rightmost half of object }
else
edge := kLeadingEdge; { point is past object }
end;
{$ELSEC}
{ find out whether the point is in the leftmost quarter of the object, }
{ in the middle half, in the rightmost quarter or past the object }
subWidth := BSR(objectWidth, 2); { divide by four }
if (pixelWidth + subWidth < 0) then
begin
WEGetOffset := segmentStart;
if (pixelWidth + objectWidth < subWidth) then
edge := kLeadingEdge { point is in leftmost quarter of object }
else
edge := kObjectEdge; { point is in middle half of object }
end
else
begin
WEGetOffset := segmentStart + 1;
if (pixelWidth < 0) then
edge := kTrailingEdge { point is in rightmost quarter of object }
else
edge := kLeadingEdge; { point is past object }
end;
{$ENDC}
end { EMBEDDED OBJECT }
else
begin
{ REGULAR TEXT }
{ if this is the last segment on the line, strip the last blank character (if any), }
{ unless it is the last non-CR character in the whole text stream }
if (not Odd(styleRunPosition)) then
if (segmentStart + segmentLength < pWE^.textLength) | (Ptr(LongInt(pSegment) + segmentLength - 1)^ = kEOL) then
begin
cType := CallWECharTypeProc(pSegment, segmentLength - 1, FontScript, hWE, pWE^.charTypeHook);
if (BAND(cType, smcTypeMask + smcClassMask) = smCharPunct + smPunctBlank) then
if (BAND(cType, smcDoubleMask) = 0) then
segmentLength := segmentLength - 1
else
segmentLength := segmentLength - 2;
end;
{ calculate slop for this text segment (justified text only) }
if (pWE^.alignment = weJustify) then
slop := FixMul(PortionLine(pSegment, segmentLength, styleRunPosition, Point(kOneToOneScaling), Point(kOneToOneScaling)), pLine^.lineJustAmount)
else
slop := 0;
{$IFC WASTE_DEBUG}
_WEAssert(pWE^.pixelToCharHook <> nil, 'Missing PixelToChar Hook');
{$ENDC}
{ call PixelToChar hook for this segment }
WEGetOffset := segmentStart + CallWEPixelToCharProc(pSegment, segmentLength, slop, pixelWidth, edge, styleRunPosition, hPos, hWE, pWE^.pixelToCharHook);
end; { REGULAR TEXT }
{ increment hPos by change in pixelWidth }
hPos := hPos + (oldWidth - pixelWidth);
{ if pixelWidth has gone negative, we're finished; otherwise go to next run }
if (pixelWidth < 0) then
SLPixelToChar := true;
end; { SLPixelToChar }
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ offset thePoint so that it is relative to the top left corner of the destination rectangle }
thePoint.v := thePoint.v - pWE^.destRect.top;
thePoint.h := thePoint.h - pWE^.destRect.left;
{ if the point is above the destination rect, return zero }
if (thePoint.v < 0) then
begin
WEGetOffset := 0;
edge := kTrailingEdge;
end
else
{ if the point is below the last line, return last char offset }
if (thePoint.v >= WEGetHeight(0, maxLongInt, hWE)) then
begin
WEGetOffset := pWE^.textLength;
edge := kLeadingEdge;
end
else
begin
{ find the line index corresponding to the vertical pixel offset }
lineIndex := _WEPixelToLine(thePoint.v, hWE);
{ express the horizontal pixel offset as a Fixed value }
pixelWidth := BSL(thePoint.h, 16);
hPos := 0;
{ walk through the segments on this line calling PixelToChar }
_WESegmentLoop(lineIndex, lineIndex, SLPixelToChar, hWE);
end; { else }
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEGetOffset }
procedure WEGetPoint (offset: LongInt;
var thePoint: LongPt;
var lineHeight: Integer;
hWE: WEHandle);
{ given a byte offset into the text, find the corresponding glyph position }
{ this routine is useful for highlighting the text and for positioning the caret }
var
pWE: WEPtr;
pLine: LinePeek;
lineIndex: LongInt;
saveWELock: Boolean;
function SLCharToPixel (pLine: LinePtr;
pAttrs: WERunAttributesPtr;
pSegment: Ptr;
segmentStart, segmentLength: LongInt;
styleRunPosition: JustStyleCode): Boolean;
var
slop: Fixed;
width: Integer;
isInSegment: Boolean;
begin
{ is offset within this segment? }
isInSegment := (offset < segmentStart + segmentLength);
{ if this is the first style run on the line, add pen indent to thePoint.h }
if (styleRunPosition <= leftStyleRun) then
thePoint.h := thePoint.h + _WECalcPenIndent(pLine^.lineSlop, pWE^.alignment);
if (pAttrs^.runStyle.tsObject <> kNullObject) then
begin
{ EMBEDDED OBJECT }
if (isInSegment) then
width := 0
else
width := WEObjectDescHandle(pAttrs^.runStyle.tsObject)^^.objectSize.h;
end
else
begin
{ REGULAR TEXT }
{ calculate slop for this text segment (justified text only) }
if (pWE^.alignment = weJustify) then
slop := FixMul(PortionLine(pSegment, segmentLength, styleRunPosition, Point(kOneToOneScaling), Point(kOneToOneScaling)), pLine^.lineJustAmount)
else
slop := 0;
{$IFC WASTE_DEBUG}
_WEAssert(pWE^.charToPixelHook <> nil, 'Missing CharToPixel Hook');
{$ENDC}
{ call CharToPixel hook to get width of segment up to specified offset }
width := CallWECharToPixelProc(pSegment, segmentLength, slop, offset - segmentStart, hilite, styleRunPosition, thePoint.h, hWE, pWE^.charToPixelHook);
end;
{ advance thePoint.h by the width of this segment }
thePoint.h := thePoint.h + width;
{ drop out of loop when we reach offset }
SLCharToPixel := isInSegment;
end; { SLCharToPixel }
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ the base point is the top left corner of the destination rectangle }
thePoint := pWE^.destRect.topLeft;
{ first of all find the line on which the glyph lies }
lineIndex := WEOffsetToLine(offset, hWE);
{ calculate the vertical coordinate and the line height }
pLine := @pWE^.hLines^^[lineIndex];
thePoint.v := thePoint.v + pLine^.first.lineOrigin;
lineHeight := pLine^.second.lineOrigin - pLine^.first.lineOrigin;
if ((offset = pWE^.textLength) & (WEGetChar(offset - 1, hWE) = CHR(kEOL))) then
begin
{ SPECIAL CASE: if offset is past the last character and }
{ the last character is a carriage return, return a point below the last line }
thePoint.v := thePoint.v + lineHeight;
thePoint.h := thePoint.h + _WECalcPenIndent(pWE^.destRect.right - pWE^.destRect.left, pWE^.alignment);
end
else
{ to get the horizontal coordinate, walk through the style runs on this line }
_WESegmentLoop(lineIndex, lineIndex, SLCharToPixel, hWE);
{ pin the horizontal coordinate to the destination rectangle }
thePoint.h := _WEPinInRange(thePoint.h, pWE^.destRect.left, pWE^.destRect.right);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEGetPoint }
procedure WEFindLine (offset: LongInt;
edge: SignedByte;
var lineStart, lineEnd: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
pLine: LineArrayPtr;
begin
pWE := hWE^;
pLine := @pWE^.hLines^^[WEOffsetToLine(offset, hWE)];
lineStart := pLine^[0].lineStart;
lineEnd := pLine^[1].lineStart;
end; { WEFindLine }
function _WEGetContext (offset: LongInt;
var contextStart, contextEnd: LongInt;
hWE: WEHandle): ScriptCode;
{ This function finds a range of characters ("context"), all belonging to the same script }
{ and centered around the specified offset. }
{ The function result is the ID of a font belonging to this script. }
{ Ideally, the context should consist of a whole script run, but in practice the returned }
{ context can be narrower, for performance and other reasons (see below) }
var
index, saveIndex, saveRunEnd: LongInt;
runInfo: WERunInfo;
script1, script2: ScriptCode;
begin
if BTST(hWE^^.flags, weFNonRoman) then
begin
{ if more than one script is installed, limit the search of script run boundaries }
{ to a single line, for speed's sake }
WEFindLine(offset, kLeadingEdge, contextStart, contextEnd, hWE);
{ find the style run the specified offset is in }
index := _WEOffsetToRun(offset, hWE);
_WEGetIndStyle(index, runInfo, hWE);
{ find the script code associated with this style run }
script1 := FontToScript(runInfo.runAttrs.runStyle.tsFont);
{ the script code is returned as function result }
_WEGetContext := script1;
{ save index and runInfo.runEnd for the second while loop }
saveIndex := index;
saveRunEnd := runInfo.runEnd;
{ walk backwards across style runs preceding offset, looking for a script run boundary }
while (runInfo.runStart > contextStart) do
begin
index := index - 1;
_WEGetIndStyle(index, runInfo, hWE);
script2 := FontToScript(runInfo.runAttrs.runStyle.tsFont);
if (script1 <> script2) then
begin
contextStart := runInfo.runEnd;
Leave;
end;
end; { while }
{ restore index and runInfo.runEnd }
index := saveIndex;
runInfo.runEnd := saveRunEnd;
{ walk forward across style runs following offset, looking for a script run boundary }
while (runInfo.runEnd < contextEnd) do
begin
index := index + 1;
_WEGetIndStyle(index, runInfo, hWE);
script2 := FontToScript(runInfo.runAttrs.runStyle.tsFont);
if (script1 <> script2) then
begin
contextEnd := runInfo.runStart;
Leave;
end;
end; { while }
end
else
begin
{ only the Roman script is enabled: the whole text constitutes one script run }
_WEGetContext := smRoman;
contextStart := 0;
contextEnd := hWE^^.textLength;
end;
{ make sure the range identified by contextStart/contextEnd is contained within }
{ the 32K byte range centered around the specified offset }
{ the reason for this is that many Script Manager routines (e.g. FindWord and CharByte) }
{ only accept 16-bit offsets, rather than 32-bit offsets }
contextStart := _WEPinInRange(contextStart, offset - (maxint div 2), offset);
contextEnd := _WEPinInRange(contextEnd, offset, offset + (maxint div 2));
end; { _WEGetContext }
function _WEGetRestrictedContext (offset: LongInt;
var contextStart, contextEnd: LongInt;
hWE: WEHandle): ScriptCode;
{ This function finds a range of characters ("context"), all belonging to the same script }
{ and centered around the specified offset. }
{ This function returns a script run subrange and is more efficient than }
{ _WEGetContext because it doesn't try to find the script boundaries accurately. }
var
runInfo: WERunInfo;
begin
{ just find the style run the specified offset is in }
WEGetRunInfo(offset, runInfo, hWE);
contextStart := runInfo.runStart;
contextEnd := runInfo.runEnd;
_WEGetRestrictedContext := FontToScript(runInfo.runAttrs.runStyle.tsFont);
{ make sure the range identified by contextStart/contextEnd is contained within }
{ the 32K byte range centered around the specified offset }
{ the reason for this is that many Script Manager routines (e.g. FindWord and CharByte) }
{ only accept 16-bit offsets, rather than 32-bit offsets }
contextStart := _WEPinInRange(contextStart, offset - (maxint div 2), offset);
contextEnd := _WEPinInRange(contextEnd, offset, offset + (maxint div 2));
end; { _WEGetRestrictedContext }
procedure WEFindWord (offset: LongInt;
edge: SignedByte;
var wordStart, wordEnd: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
script: ScriptCode;
contextStart, contextEnd: LongInt;
hText: Handle;
wordBreaks: OffsetTable;
saveWELock, saveTextLock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ find a script context containing the specified offset }
{ (words cannot straddle script boundaries) }
script := _WEGetContext(offset, contextStart, contextEnd, hWE);
{ lock the text }
hText := pWE^.hText;
saveTextLock := _WESetHandleLock(hText, true);
{ call the word break hook }
CallWEWordBreakProc(Ptr(LongInt(hText^) + contextStart), contextEnd - contextStart, offset - contextStart, edge, wordBreaks, script, hWE, pWE^.wordBreakHook);
{ unlock the text }
if (_WESetHandleLock(hText, saveTextLock)) then
;
{ calculate wordStart and wordEnd relative to the beginning of the text }
wordStart := contextStart + wordBreaks[0].offFirst;
wordEnd := contextStart + wordBreaks[0].offSecond;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEFindWord }
function WECharByte (offset: LongInt;
hWE: WEHandle): Integer;
var
pWE: WEPtr;
script: ScriptCode;
contextStart, contextEnd: LongInt;
hText: Handle;
saveWELock, saveTextLock: Boolean;
begin
WECharByte := smSingleByte;
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ do nothing unless there is at least one double-byte script system installed }
{ and make sure offset is within allowed bounds }
if (BTST(pWE^.flags, weFDoubleByte)) then
if ((offset >= 0) and (offset < pWE^.textLength)) then
begin
{ find a script context containing the specified offset }
script := _WEGetRestrictedContext(offset, contextStart, contextEnd, hWE);
{ lock the text }
hText := pWE^.hText;
saveTextLock := _WESetHandleLock(hText, true);
{ pass the CharByte hook a pointer to the beginning of the style run }
WECharByte := CallWECharByteProc(Ptr(LongInt(hText^) + contextStart), offset - contextStart, script, hWE, pWE^.charByteHook);
{ unlock the text }
if (_WESetHandleLock(hText, saveTextLock)) then
;
end;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WECharByte }
function WECharType (offset: LongInt;
hWE: WEHandle): Integer;
var
pWE: WEPtr;
script: ScriptCode;
contextStart, contextEnd: LongInt;
hText: Handle;
saveWELock, saveTextLock: Boolean;
begin
WECharType := 0;
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ make sure offset is within allowed bounds }
if ((offset >= 0) and (offset < pWE^.textLength)) then
begin
{ find a script context containing the specified offset }
script := _WEGetRestrictedContext(offset, contextStart, contextEnd, hWE);
{ lock the text }
hText := pWE^.hText;
saveTextLock := _WESetHandleLock(hText, true);
{ pass the CharType hook a pointer to the beginning of the style run }
WECharType := CallWECharTypeProc(Ptr(LongInt(hText^) + contextStart), offset - contextStart, script, hWE, pWE^.charTypeHook);
{ unlock the text }
if (_WESetHandleLock(hText, saveTextLock)) then
;
end;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WECharType }
procedure _WEDrawCaret (offset: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
thePoint: LongPt;
caretRect: Rect;
caretHeight: Integer;
savePort: GrafPtr;
saveClip: RgnHandle;
begin
{ the WE record must be already locked }
pWE := hWE^;
{ find the caret position using WEGetPoint }
WEGetPoint(offset, thePoint, caretHeight, hWE);
WELongPointToPoint(thePoint, caretRect.topLeft);
if (caretRect.left > pWE^.destRect.left) then
caretRect.left := caretRect.left - 1;
{ calculate caret rectangle }
caretRect.bottom := caretRect.top + caretHeight;
caretRect.right := caretRect.left + kCaretWidth;
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ clip to the view region }
saveClip := NewRgn;
GetClip(saveClip);
SetClip(pWE^.viewRgn);
{ draw the caret }
InvertRect(caretRect);
{ restore the clip region }
SetClip(saveClip);
DisposeRgn(saveClip);
{ restore the port }
SetPort(savePort);
end; { _WEDrawCaret }
procedure _WEBlinkCaret (hWE: WEHandle);
var
pWE: WEPtr;
begin
{ the WE record must be already locked }
pWE := hWE^;
{ do nothing if we're not active }
if (not BTST(pWE^.flags, weFActive)) then
Exit(_WEBlinkCaret);
{ redraw the caret, in XOR mode }
_WEDrawCaret(pWE^.selStart, hWE);
{ keep track of the current caret visibility status }
pWE^.flags := BXOR(pWE^.flags, BSL(1, weFCaretVisible));
{ update caretTime }
pWE^.caretTime := TickCount;
end; { _WEBlinkCaret }
function WEGetHiliteRgn (rangeStart, rangeEnd: LongInt;
hWE: WEHandle): RgnHandle;
{ returns the hilite region corresponding to the specified range }
{ the caller is responsible for disposing of the returned region }
{ when it's finished with it }
var
pWE: WEPtr;
hiliteRgn: RgnHandle;
selRect: LongRect;
firstPoint, lastPoint: LongPt;
firstLineHeight, lastLineHeight: Integer;
r: Rect;
savePort: GrafPtr;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ make sure rangeStart comes before rangeEnd }
_WEReorder(rangeStart, rangeEnd);
{ calculate pixel location corresponding to rangeStart }
WEGetPoint(rangeStart, firstPoint, firstLineHeight, hWE);
{ calculate pixel location corresponding to rangeEnd }
WEGetPoint(rangeEnd, lastPoint, lastLineHeight, hWE);
{ open a region: rects to be hilited will be accumulated in this }
OpenRgn;
if (firstPoint.v = lastPoint.v) then
begin
{ selection range encompasses only one line }
WESetLongRect(selRect, firstPoint.h, firstPoint.v, lastPoint.h, lastPoint.v + lastLineHeight);
WELongRectToRect(selRect, r);
FrameRect(r);
end
else
begin
{ selection range encompasses more than one line }
{ hilite the first line }
WESetLongRect(selRect, firstPoint.h, firstPoint.v, pWE^.destRect.right, firstPoint.v + firstLineHeight);
WELongRectToRect(selRect, r);
FrameRect(r);
{ any lines between the first and the last one? }
if (firstPoint.v + firstLineHeight < lastPoint.v) then
begin
{ hilite all the lines in-between }
WESetLongRect(selRect, pWE^.destRect.left, firstPoint.v + firstLineHeight, pWE^.destRect.right, lastPoint.v);
WELongRectToRect(selRect, r);
FrameRect(r);
end;
{ hilite the last line }
WESetLongRect(selRect, pWE^.destRect.left, lastPoint.v, lastPoint.h, lastPoint.v + lastLineHeight);
WELongRectToRect(selRect, r);
FrameRect(r);
end;
{ copy the accumulated region into a new region }
hiliteRgn := NewRgn;
CloseRgn(hiliteRgn);
{ restrict this region to the view region }
SectRgn(hiliteRgn, pWE^.viewRgn, hiliteRgn);
{ restore the port }
SetPort(savePort);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
{ return the hilite region }
WEGetHiliteRgn := hiliteRgn;
end; { WEGetHiliteRgn }
procedure _WEHiliteRange (rangeStart, rangeEnd: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
saveClip, auxRgn, hiliteRgn: RgnHandle;
savePen: PenState;
savePort: GrafPtr;
begin
{ the WE record must be already locked }
pWE := hWE^;
{ do nothing if the specified range is empty }
if (rangeStart = rangeEnd) then
Exit(_WEHiliteRange);
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ create auxiliary regions }
saveClip := NewRgn;
auxRgn := NewRgn;
{ restrict the clip region to the view rectangle }
GetClip(saveClip);
SectRgn(saveClip, pWE^.viewRgn, auxRgn);
SetClip(auxRgn);
{ get the hilite region corresponding to the specified range }
hiliteRgn := WEGetHiliteRgn(rangeStart, rangeEnd, hWE);
{ hilite the region or frame it, depending on the setting of the active flag }
if BTST(pWE^.flags, weFActive) then
begin
_WEClearHiliteBit;
InvertRgn(hiliteRgn);
end
else if BTST(pWE^.flags, weFOutlineHilite) then
begin
GetPenState(savePen);
PenNormal;
PenMode(patXor);
_WEClearHiliteBit;
FrameRgn(hiliteRgn);
SetPenState(savePen);
end;
{ restore the clip region }
SetClip(saveClip);
{ dispose of all regions }
DisposeRgn(saveClip);
DisposeRgn(auxRgn);
DisposeRgn(hiliteRgn);
{ restore the port }
SetPort(savePort);
end; { _WEHiliteRange }
procedure WESetSelection (selStart, selEnd: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
oldSelStart, oldSelEnd: LongInt;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ range-check parameters }
selStart := _WEPinInRange(selStart, 0, pWE^.textLength);
selEnd := _WEPinInRange(selEnd, 0, pWE^.textLength);
{ set the weFAnchorIsEnd bit if selStart > selEnd, then reorder the endpoints }
if (selStart > selEnd) then
BSET(pWE^.flags, weFAnchorIsEnd)
else
BCLR(pWE^.flags, weFAnchorIsEnd);
_WEReorder(selStart, selEnd);
{ get old selection range }
oldSelStart := pWE^.selStart;
oldSelEnd := pWE^.selEnd;
{ selection changed? }
if ((oldSelStart <> selStart) or (oldSelEnd <> selEnd)) then
begin
{ invalid the null style }
BCLR(pWE^.flags, weFUseNullStyle);
{ hide the caret if it's showing }
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
{ set new selection range }
pWE^.selStart := selStart;
pWE^.selEnd := selEnd;
{ skip this section if redrawing has been inhibited }
if (not BTST(pWE^.flags, weFInhibitRecal)) then
begin
{ if we're active, invert the exclusive-OR between the old range and the new range. }
{ if we're inactive, this optimization can't be used because of outline highlighting. }
if BTST(pWE^.flags, weFActive) then
begin
_WEReorder(oldSelStart, selStart);
_WEReorder(oldSelEnd, selEnd);
_WEReorder(oldSelEnd, selStart);
end;
_WEHiliteRange(oldSelStart, oldSelEnd, hWE);
_WEHiliteRange(selStart, selEnd, hWE);
if (not BTST(pWE^.flags, weFMouseTracking)) then
begin
{ redraw the caret immediately, if the selection range is empty }
if (pWE^.selStart = pWE^.selEnd) then
_WEBlinkCaret(hWE);
{ clear clickCount, unless we're tracking the mouse }
pWE^.clickCount := 0;
{ scroll the selection into view, unless we're tracking the mouse }
WESelView(hWE);
end;
end; { if redrawing not inhibited }
end; { if selection changed }
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WESetSelection }
procedure WESetAlignment (alignment: SignedByte;
hWE: WEHandle);
var
pWE: WEPtr;
oldAlignment: Integer;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
oldAlignment := pWE^.alignment;
if ((alignment >= weFlushLeft) and (alignment <= weJustify) and (alignment <> oldAlignment)) then
begin
{ hide the caret if it's showing }
if (BTST(pWE^.flags, weFCaretVisible)) then
_WEBlinkCaret(hWE);
{ change the alignment }
pWE^.alignment := alignment;
{ if the text was left-aligned, then we haven't been bothering till now, }
{ so we have to recalc the whole document }
if (oldAlignment = weFlushLeft) then
_WERecalSlops(0, pWE^.nLines - 1, hWE);
{ redraw the view rectangle }
WEUpdate(nil, hWE);
end;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WESetAlignment }
function _WEArrowOffset (action: Integer;
offset: LongInt;
hWE: WEHandle): LongInt;
{ given an action code (corresponding to a modifiers + arrow key combo) }
{ and an offset into the text, find the offset of the new caret position }
var
thePoint: LongPt;
textLength, rangeStart, rangeEnd: LongInt;
lineHeight: Integer;
edge: SignedByte;
begin
textLength := hWE^^.textLength;
case action of
kGoLeft:
if (offset > 0) then
begin
offset := offset - 1;
if (WECharByte(offset, hWE) <> smSingleByte) then
offset := offset - 1;
end;
kGoRight:
if (offset < textLength) then
begin
if (WECharByte(offset, hWE) <> smSingleByte) then
offset := offset + 1;
offset := offset + 1;
end;
kGoUp:
begin
WEGetPoint(offset, thePoint, lineHeight, hWE);
thePoint.v := thePoint.v - 1;
offset := WEGetOffset(thePoint, edge, hWE);
end;
kGoDown:
begin
WEGetPoint(offset, thePoint, lineHeight, hWE);
thePoint.v := thePoint.v + lineHeight;
offset := WEGetOffset(thePoint, edge, hWE);
end;
kGoWordStart:
begin
WEFindWord(offset, kTrailingEdge, rangeStart, rangeEnd, hWE);
offset := rangeStart;
end;
kGoWordEnd:
begin
WEFindWord(offset, kLeadingEdge, rangeStart, rangeEnd, hWE);
offset := rangeEnd;
end;
kGoTextStart:
offset := 0;
kGoTextEnd:
offset := textLength;
kGoLineStart:
begin
WEFindLine(offset, kLeadingEdge, rangeStart, rangeEnd, hWE);
offset := rangeStart;
end;
kGoLineEnd:
begin
WEFindLine(offset, kTrailingEdge, rangeStart, rangeEnd, hWE);
offset := rangeEnd;
if (offset < textLength) then
begin
offset := offset - 1;
if (WECharByte(offset, hWE) <> smSingleByte) then
offset := offset - 1;
end;
end;
otherwise
;
end; { case action }
_WEArrowOffset := offset;
end; { _WEArrowOffset }
procedure _WEDoArrowKey (arrow: Integer;
modifiers: Integer;
hWE: WEHandle);
{ this routine is called by WEKey to handle arrow keys }
{ the WE record is guaranteed to be already locked }
var
pWE: WEPtr;
action: Integer;
selStart, selEnd: LongInt;
caretLoc, anchor: LongInt;
begin
pWE := hWE^;
{ calculate the "action" parameter for _WEArrowOffset from arrow and modifiers }
action := arrow - kArrowLeft; { possible range: 0..3 }
if (BAND(modifiers, optionKey) <> 0) then
action := action + kOption;
if (BAND(modifiers, cmdKey) <> 0) then
action := action + kCommand;
{ get selection range }
selStart := pWE^.selStart;
selEnd := pWE^.selEnd;
if (BAND(modifiers, shiftKey) = 0) then
begin
{ if selection range isn't empty, collapse it to one of the endpoints }
if (selStart < selEnd) then
if ((arrow = kArrowLeft) or (arrow = kArrowUp)) then
caretLoc := selStart
else
caretLoc := selEnd
else
{ otherwise move the insertion point }
caretLoc := _WEArrowOffset(action, selStart, hWE);
{ set anchor to caretLoc, so new selection will be empty }
anchor := caretLoc;
end
else
begin
{ shift key was held down: extend the selection rather than replacing it }
{ find out which selection boundary is the anchor and which is the free endpoint }
if BTST(pWE^.flags, weFAnchorIsEnd) then
begin
anchor := selEnd;
caretLoc := selStart;
end
else
begin
anchor := selStart;
caretLoc := selEnd;
end;
{ move the free endpoint }
caretLoc := _WEArrowOffset(action, caretLoc, hWE);
end;
{ select the new selection }
WESetSelection(anchor, caretLoc, hWE);
end; { _WEDoArrowKey }
function WEAdjustCursor (mouseLoc: Point;
mouseRgn: RgnHandle;
hWE: WEHandle): Boolean;
{ Call WEAdjustCursor to set the cursor shape when the mouse is in the view rectangle. }
{ MouseRgn should be either a valid region handle or NIL. }
{ If mouseRgn is supplied (i.e., if it's not NIL), it is intersected with a region }
{ in global coordinates within which the cursor is to retain its shape. }
{ WEAdjustCursor returns TRUE if the cursor has been set. }
{ Your application should set the cursor only if WEAdjustCursor returns FALSE. }
var
pWE: WEPtr;
auxRgn, hiliteRgn: RgnHandle;
cursorType: (kIBeam, kArrow);
portDelta: Point;
savePort: GrafPtr;
saveWELock: Boolean;
begin
WEAdjustCursor := false;
cursorType := kIBeam;
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ calculate delta between the local coordinate system and the global one }
portDelta := Point(0);
LocalToGlobal(portDelta);
{ calculate the visible portion of the view rectangle, in global coordinates }
auxRgn := NewRgn;
CopyRgn(pWE^.viewRgn, auxRgn);
SectRgn(auxRgn, pWE^.port^.visRgn, auxRgn);
OffsetRgn(auxRgn, portDelta.h, portDelta.v);
if (PtInRgn(mouseLoc, auxRgn)) then
begin
{ mouse is within view rectangle: it's up to us to set the cursor }
WEAdjustCursor := true;
{ if drag-and-drop is enabled, see if the mouse is within current selection }
if (BTST(pWE^.flags, weFHasDragManager) and BTST(pWE^.flags, weFDragAndDrop)) then
if (pWE^.selStart < pWE^.selEnd) then
begin
{ get current hilite region in global coordinates }
hiliteRgn := WEGetHiliteRgn(pWE^.selStart, pWE^.selEnd, hWE);
OffsetRgn(hiliteRgn, portDelta.h, portDelta.v);
{ if mouse is within selection, set cursor to an arrow, else to an I-beam }
{ (actually, we still use an I-beam if less than DoubleTime ticks have elapsed }
{ since the last mouse click, so that the cursor doesn't turn into an arrow while }
{ triple-clicking + dragging a range of lines) }
if (PtInRgn(mouseLoc, hiliteRgn) and ((TickCount > pWE^.clickTime + GetDblTime) or (pWE^.clickEdge = kObjectEdge))) then
begin
cursorType := kArrow; { use arrow cursor }
CopyRgn(hiliteRgn, auxRgn);
end
else
DiffRgn(auxRgn, hiliteRgn, auxRgn);
{ dispose of the hilite region }
DisposeRgn(hiliteRgn);
end; { if drag-and-drop is enabled }
{ set the cursor }
if (cursorType = kIBeam) then
SetCursor(GetCursor(iBeamCursor)^^)
else
SetCursor(GetQDGlobalsPtr^.arrow);
{ set mouseRgn, if provided }
if (mouseRgn <> nil) then
SectRgn(mouseRgn, auxRgn, mouseRgn);
end
else
{ mouse is outside view rectangle: don't set the cursor; subtract viewRgn from mouseRgn }
if (mouseRgn <> nil) then
DiffRgn(mouseRgn, auxRgn, mouseRgn);
{ dispose of the temporary region }
DisposeRgn(auxRgn);
{ restore the port }
SetPort(savePort);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEAdjustCursor }
procedure WEIdle (var maxSleep: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
caretInterval, sleepTime: LongInt;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{$IFC WASTE_DEBUG}
_WESanityCheck(hWE);
{$ENDC}
{ the caret blinks only if we're active and the selection point is empty }
if (BTST(pWE^.flags, weFActive) and (pWE^.selStart = pWE^.selEnd)) then
begin
{ the low-memory global variable CaretTime contains the preferred interval }
{ between successive inversions of the caret }
caretInterval := GetCaretTime;
{ calculate how many ticks we can sleep before we need to invert the caret }
{ the caretTime field of the WE record contains the time of the last inversion }
sleepTime := caretInterval - (TickCount - pWE^.caretTime);
{ if sleepTime has gone negative, invert the caret }
if (sleepTime <= 0) then
begin
_WEBlinkCaret(hWE);
sleepTime := caretInterval;
end;
end
else
{ if we don't need to blink the caret, we can sleep forever }
sleepTime := maxLongInt;
{ return sleepTime to the caller if maxSleep isn't NIL }
if (@maxSleep <> nil) then
maxSleep := sleepTime;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEIdle }
procedure WEUpdate (updateRgn: RgnHandle;
hWE: WEHandle);
var
pWE: WEPtr;
firstLine, lastLine: LongInt;
auxRect: Rect;
saveClip, auxRgn: RgnHandle;
savePort: GrafPtr;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ save the clip region }
saveClip := NewRgn;
GetClip(saveClip);
{ clip to the insersection between updateRgn and the view rectangle }
{ (updateRgn may be NIL; in this case, just clip to the view rectangle) }
auxRgn := NewRgn;
if (updateRgn <> nil) then
SectRgn(updateRgn, pWE^.viewRgn, auxRgn)
else
CopyRgn(pWE^.viewRgn, auxRgn);
SetClip(auxRgn);
if (EmptyRgn(auxRgn) = false) then
begin
{ set auxRect to the bounding box of the update region (clipped to the view rectangle) }
auxRect := auxRgn^^.rgnBBox;
{ find out which lines need to be redrawn }
firstLine := _WEPixelToLine(auxRect.top - pWE^.destRect.top, hWE);
lastLine := _WEPixelToLine((auxRect.bottom - 1) - pWE^.destRect.top, hWE);
{ draw them (if updateRgn is NIL, erase each line rectangle before redrawing) }
_WEDrawLines(firstLine, lastLine, (updateRgn = nil), hWE);
{ hilite the selection range or draw the caret (only if active) }
if (pWE^.selStart < pWE^.selEnd) then
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE)
else if BTST(pWE^.flags, weFCaretVisible) then
begin
_WEBlinkCaret(hWE);
BSET(pWE^.flags, weFCaretVisible);
end;
end; { if not empty }
DisposeRgn(auxRgn);
{ restore the clip region }
SetClip(saveClip);
DisposeRgn(saveClip);
{ restore the port }
SetPort(savePort);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEUpdate }
procedure WEDeactivate (hWE: WEHandle);
var
pWE: WEPtr;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ do nothing if we are already inactive }
if (BTST(pWE^.flags, weFActive)) then
begin
{ hide the selection range or the caret }
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
{ clear the active flag }
BCLR(pWE^.flags, weFActive);
{ frame the selection }
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
{ dispose of the offscreen graphics world, if any }
if (pWE^.offscreenPort <> nil) then
begin
DisposeGWorld(GWorldPtr(pWE^.offscreenPort));
pWE^.offscreenPort := nil;
end;
{ notify Text Services }
if (pWE^.tsmReference <> nil) then
if (DeactivateTSMDocument(pWE^.tsmReference) <> noErr) then
;
end;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEDeactivate }
procedure WEActivate (hWE: WEHandle);
var
pWE: WEPtr;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ do nothing if we are already active }
if (not BTST(pWE^.flags, weFActive)) then
begin
{ remove the selection frame }
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
{ set the active flag }
BSET(pWE^.flags, weFActive);
{ show the selection range }
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
{ notify Text Services }
if (pWE^.tsmReference <> nil) then
if (ActivateTSMDocument(pWE^.tsmReference) <> noErr) then
;
end;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEActivate }
function WEIsActive (hWE: WEHandle): Boolean;
begin
{ return TRUE iff the specified WE instance is currently active }
WEIsActive := BTST(hWE^^.flags, weFActive);
end; { WEIsActive }
procedure WEScroll (hOffset, vOffset: LongInt;
hWE: WEHandle);
var
pWE: WEPtr;
viewRect: Rect;
updateRgn: RgnHandle;
savePort: GrafPtr;
hideOutline, saveWELock: Boolean;
begin
{ do nothing if both scroll offsets are zero }
if ((hOffset = 0) and (vOffset = 0)) then
Exit(WEScroll);
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ hide the caret if it's showing }
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ if we're inactive and outline highlighting is on, we have to temporarily }
{ hide the selection outline while scrolling to avoid a cosmetic bug }
hideOutline := false;
if (not BTST(pWE^.flags, weFActive)) then
if (BTST(pWE^.flags, weFOutlineHilite)) then
begin
hideOutline := true;
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
BCLR(pWE^.flags, weFOutlineHilite);
end;
{ if we're currently tracking a drag, notify the Drag Manager we're about to scroll }
if (pWE^.currentDrag <> kNullDrag) then
if (DragPreScroll(pWE^.currentDrag, hOffset, vOffset) <> noErr) then
;
viewRect := pWE^.viewRgn^^.rgnBBox;
updateRgn := NewRgn;
{ offset the destination rectangle by the specified amount }
WEOffsetLongRect(pWE^.destRect, hOffset, vOffset);
{ scroll the view rectangle }
ScrollRect(viewRect, hOffset, vOffset, updateRgn);
{ redraw the exposed region }
WEUpdate(updateRgn, hWE);
DisposeRgn(updateRgn);
{ notify the Drag Manager }
if (pWE^.currentDrag <> kNullDrag) then
if (DragPostScroll(pWE^.currentDrag) <> noErr) then
;
{ redraw the selection outline, if hidden }
if (hideOutline) then
begin
BSET(pWE^.flags, weFOutlineHilite);
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
end;
{ restore the port }
SetPort(savePort);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEScroll }
function _WEScrollIntoView (offset: LongInt;
hWE: WEHandle): Boolean;
var
pWE: WEPtr;
thePoint: LongPt;
lineHeight: Integer;
hScroll, vScroll, temp: LongInt;
begin
pWE := hWE^;
{ do nothing if automatic scrolling is disabled }
if (not BTST(pWE^.flags, weFAutoScroll)) then
Exit(_WEScrollIntoView);
{ find the selection point }
WEGetPoint(offset, thePoint, lineHeight, hWE);
{ assume no scrolling is needed }
_WEScrollIntoView := false;
vScroll := 0;
hScroll := 0;
{ determine if we need to scroll vertically }
if (thePoint.v < pWE^.viewRect.top) or (thePoint.v + lineHeight >= pWE^.viewRect.bottom) then
begin
{ calculate the amount of vertical scrolling needed to center the selection into view }
vScroll := BSR(pWE^.viewRect.top + pWE^.viewRect.bottom, 1) - thePoint.v;
{ we'd like to superimpose the bottom margins of the dest/view rects, if possible }
temp := pWE^.viewRect.bottom - pWE^.destRect.bottom;
if (temp > vScroll) then
vScroll := temp;
{ but we also have to make sure the dest top isn't scrolled below the view top }
temp := pWE^.viewRect.top - pWE^.destRect.top;
if (temp < vScroll) then
vScroll := temp;
end;
{ determine if we need to scroll horizontally }
if (thePoint.h - 1 < pWE^.viewRect.left) or (thePoint.h >= pWE^.viewRect.right) then
begin
{ calculate the amount of horizontal scrolling needed to center the selection into view }
hScroll := BSR(pWE^.viewRect.left + pWE^.viewRect.right, 1) - thePoint.h;
{ we'd like to superimpose the right margins of the dest/view rects, if possible }
temp := pWE^.viewRect.right - pWE^.destRect.right;
if (temp > hScroll) then
hScroll := temp;
{ but we also have to make sure the dest left isn't scrolled to the right of the view left }
temp := pWE^.viewRect.left - pWE^.destRect.left;
if (temp < hScroll) then
hScroll := temp;
end;
{ scroll the text if necessary }
if ((vScroll <> 0) or (hScroll <> 0)) then
begin
_WEScrollIntoView := true;
WEScroll(hScroll, vScroll, hWE);
BSET(pWE^.flags, weFDestRectChanged);
end;
{ notify our client of changes to the destination rectangle }
if (BTST(pWE^.flags, weFDestRectChanged)) then
begin
if (pWE^.scrollProc <> nil) then
CallWEScrollProc(hWE, pWE^.scrollProc);
BCLR(pWE^.flags, weFDestRectChanged);
end;
end; { _WEScrollIntoView }
procedure WESelView (hWE: WEHandle);
var
pWE: WEPtr;
offset: LongInt;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ scroll the free endpoint of the selection into view }
if (BTST(pWE^.flags, weFAnchorIsEnd)) then
offset := pWE^.selStart
else
offset := pWE^.selEnd;
if (_WEScrollIntoView(offset, hWE)) then
;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WESelView }
end.